#pragma once

//namespace my {

//using namespace std;

template <class T>
class  Vector
{
public:

	typedef T * iterator;

	Vector();
	Vector(unsigned int size);
	Vector(unsigned int size, const T & initial);
	Vector(const Vector<T> & v);
	~Vector();

	unsigned int capacity() const;
	unsigned int size() const;
	bool empty() const;
	iterator begin();
	iterator end();
	T & front();
	T & back();
	int  push_back(const T & value);
	void push_front(const T & value);
	void pop_back();

	void erase(iterator position);
	void erase(const T& toDelete);


	int reserveReturnOne();
	void reserve(unsigned int capacity);
	void resize(unsigned int size);

	T & operator[](unsigned int index);
	T & at(unsigned int index);
	Vector<T> & operator=(const Vector<T> &);
	void clear();

	iterator find(iterator start, iterator end, T elementToFind);
	iterator find(T elementToFind);

private:
	unsigned int my_size;
	unsigned int my_capacity;
	T * buffer;
};

// Your code goes here ...
template<class T>
Vector<T>::Vector()
{
	my_capacity = 0;
	my_size = 0;
	buffer = 0;
}

template<class T>
Vector<T>::Vector(const Vector<T> & v)
{
	my_size = v.my_size;
	my_capacity = v.my_capacity;
	buffer = new T[my_size];
	for (unsigned int i = 0; i < my_size; i++)
		buffer[i] = v.buffer[i];
}

template<class T>
Vector<T>::Vector(unsigned int size)
{
	my_capacity = size;
	my_size = size;
	buffer = new T[size];
}

template<class T>
Vector<T>::Vector(unsigned int size, const T & initial)
{
	my_size = size;
	my_capacity = size;
	buffer = new T[size];
	for (unsigned int i = 0; i < size; i++)
		buffer[i] = initial;
	//T();
}

template<class T>
Vector<T> & Vector<T>::operator = (const Vector<T> & v)
{
	//delete[] buffer;
	my_size = v.my_size;
	my_capacity = v.my_capacity;
	buffer = new T[my_size];
	for (unsigned int i = 0; i < my_size; i++)
		buffer[i] = v.buffer[i];
	return *this;
}

template<class T>
typename Vector<T>::iterator Vector<T>::begin()
{
	return buffer;
}

template<class T>
typename Vector<T>::iterator Vector<T>::end()
{
	return buffer + size();
}

template<class T>
T& Vector<T>::front()
{
	return buffer[0];
}

template<class T>
T& Vector<T>::back()
{
	return buffer[my_size - 1];
}

template<class T>
int Vector<T>::reserveReturnOne()
{
	reserve(my_capacity + 5);
	return 1;
}

template<class T>
int Vector<T>::push_back(const T & v)
{
	int notImportant = (my_size >= my_capacity) ? reserveReturnOne() : 2;

	//if (my_size >= my_capacity)
	//{
	//	reserve(my_capacity + 5);
	//}
	buffer[my_size++] = v;
	return 1;
}

template<class T>
void Vector<T>::pop_back()
{
	my_size--;
}

template<class T>
void Vector<T>::push_front(const T & v)
{
	//if (my_size >= my_capacity)
	//	reserve(my_capacity + 5);
	int notImportant = (my_size >= my_capacity) ? reserveReturnOne() : 2;


	T * Newbuffer = new T[my_capacity];

	for (unsigned int i = 0; i < my_size; i++)
		Newbuffer[i + 1] = buffer[i];
	Newbuffer[0] = v;

	//delete[] buffer;
	buffer = Newbuffer;
	my_size++;
}

template<class T>
void Vector<T>::reserve(unsigned int capacity)
{
	//if (buffer == 0)
	//{
	//	my_size = 0;
	//	my_capacity = 0;
	//}
	my_size = (buffer == 0) ? 0 : my_size;
	my_capacity = (buffer == 0) ? 0 : my_capacity;

	T * Newbuffer = new T[capacity];
	//assert(Newbuffer);
	unsigned int l_Size = capacity < my_size ? capacity : my_size;
	//copy (buffer, buffer + l_Size, Newbuffer);

	for (unsigned int i = 0; i < l_Size; i++)
		Newbuffer[i] = buffer[i];

	my_capacity = capacity;
	//delete[] buffer;
	buffer = Newbuffer;
}

template<class T>
unsigned int Vector<T>::size()const//
{
	return my_size;
}

template<class T>
void Vector<T>::resize(unsigned int size)
{
	reserve(size);
	my_size = size;
}

template<class T>
T& Vector<T>::operator[](unsigned int index)
{
	return buffer[index];
}

template<class T>
T& Vector<T>::at(unsigned int index)
{
	return buffer[index];
}

template<class T>
unsigned int Vector<T>::capacity()const
{
	return my_capacity;
}

template<class T>
bool Vector<T>::empty()const
{
	return my_size == 0;
}

template<class T>
typename Vector<T>::iterator Vector<T>::find(iterator start, iterator end, T elementToFind)
{
	iterator result = start;
	for (; result != end; ++result) {
		if (*result == elementToFind)
		{
			break;
		}
	}
	return result;
}

template<class T>
typename Vector<T>::iterator Vector<T>::find(T elementToFind)
{
	return find(begin(), end(), elementToFind);

}


template<class T>
void Vector<T>::erase(iterator position)
{
	// reserve more memory
	T* p = new T[my_capacity];

	// copy old data
	iterator iter;
	int oldIndex, newIndex;
	bool found = false;
	for (iter = begin(), oldIndex = 0, newIndex = 0;
		iter != end();
		++iter, ++oldIndex)
	{
		found = found || iter == position;
		if (iter != position)
		{
			T* myElem = new T(*(buffer + oldIndex));  // in-place copy-construct
			p[newIndex] = *myElem;
			++newIndex;
		}
	}

	buffer = found ? p : buffer;
	my_size = found ? my_size - 1 : my_size;
	//if (found)
	//{
	//	//delete[] buffer;
	//	buffer = p;
	//	my_size--;
	//}
}

template<class T>
void Vector<T>::erase(const T& toDelete)
{

	// reserve more memory
	T* p = new T[my_capacity];

	// copy old data
	iterator iter;
	int oldIndex, newIndex;
	bool found = false;

	for (iter = begin(), oldIndex = 0, newIndex = 0;
		iter != end();
		++iter, ++oldIndex)
	{
		found = found || *iter == toDelete;
		if (*iter != toDelete)
		{
			T* myElem = new T(*(buffer + oldIndex));  // in-place copy-construct
			p[newIndex] = *myElem;
			++newIndex;
		}
	}
	buffer = found ? p : buffer;
	my_size = found ? my_size - 1 : my_size;
	//if (found)
	//{
	//	//delete[] buffer;
	//	buffer = p;
	//	my_size--;
	//}
}


template<class T>
Vector<T>::~Vector()
{
	//delete[] buffer;
}

template <class T>
void Vector<T>::clear()
{
	//my_capacity = 0;
	//my_size = 0;
	//buffer = 0;
	my_size = 0;
	my_capacity = 5;
	buffer = new T[my_capacity];
}

//} // namespace
